package com.fubowen.reader.db.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.MapInfo
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import com.fubowen.reader.db.bean.ThemeBean
import com.fubowen.reader.db.bean.ThemeConfigBean
import com.fubowen.reader.db.model.ThemeWithValue
import com.fubowen.reader.vm.ThemeWithValueResult
import kotlinx.coroutines.flow.Flow

@Dao
interface ThemeDao {
    @Query("select * from ThemeBean")
     fun all(): List<ThemeBean>

    @Query("select * from ThemeBean where Id = :id")
     fun getById(id: Int): ThemeBean?

    @Query("select * from ThemeBean where isUsed = 1")
     fun getUsed(): ThemeBean?

    @Query("select * from ThemeBean where isUsed = 1")
     fun getUsedFlow(): Flow<ThemeBean?>

    @Query("select * from ThemeBean where name = :name limit 1")
     fun getByName(name: String): ThemeBean?

    @MapInfo(keyColumn = "name", valueTable = "Theme")
    @Query("select * from ThemeBean a  where name in (:names)")
     fun getByName(names: List<String>): Map<String, ThemeBean>

    @Insert
     fun set(bean: ThemeBean): Long

    @Update
     fun put(bean: ThemeBean)

    @Query("UPDATE ThemeBean set isUsed=:isUsed where id=:themeId")
     fun putIsUsed(themeId: Int, isUsed: Boolean)

    @Query("UPDATE ThemeBean set isUsed=0 where isUsed=1")
     fun putIsUsedToFalse()

    @Delete
     fun del(bean: ThemeBean)

    @Query("DELETE FROM ThemeBean")
     fun clear()

    //region ThemeValue

    @Query("SELECT ThemeBean.*,ThemeConfigBean.* FROM ThemeBean LEFT JOIN ThemeConfigBean ON ThemeBean.id = ThemeConfigBean.themeId where ThemeBean.id = :themeId")
     fun getThemeById(themeId: Int): ThemeWithValue?

    fun getThemeByIdToInherit(themeId: Int): ThemeWithValueResult? {
        var id = themeId
        var theme: ThemeWithValue?
        val themeList = mutableListOf<ThemeWithValue>()
        do {
            theme = getThemeById(id)
            if (theme == null) {
                break
            }
            themeList.add(theme)
            id = theme.themeBean.parentId
        } while (id != -1)

        if (themeList.isEmpty()) {
            return null
        }
        val init = mutableMapOf<String, ThemeConfigBean>()
        themeList.reversed().fold(init) { curr, next ->
            next.themeConfigBeanList.forEach {
                curr[it.key] = it
            }
            curr
        }
        return ThemeWithValueResult(
            themeBean = themeList.last().themeBean,
            themeConfigBeanList = init
        )
    }

    fun setUsedTheme(themeId: Int) {
        val theme = getUsed()
        if (theme != null) {
            if (theme.id != themeId) {
                theme.isUsed = false
                put(theme)
            }
        } else {
            putIsUsed(themeId, true)
        }
    }

    fun getUsedTheme(): ThemeWithValueResult? {
        val theme = getUsed()
        if (theme != null) {
            return getThemeByIdToInherit(theme.id)
        }
        return null
    }

    fun getThemeByNameToInherit(name: String): ThemeWithValueResult? {
        val theme = getByName(name)
        if (theme != null) {
            return getThemeByIdToInherit(theme.id)
        }
        return null
    }

    @Query("DELETE FROM ThemeConfigBean where themeId = :themeId")
    fun deleteThemeValueByThemeId(themeId: Int)

    @Insert
    fun setThemeValue(beans: List<ThemeConfigBean>)

    @Transaction
    fun putTheme(beans: List<ThemeWithValueResult>) {
        beans.forEach { item ->
            if (item.themeBean.isUsed) {
                putIsUsedToFalse()
            }
            put(item.themeBean)
            item.themeConfigBeanList.values.forEach { it.themeId = item.themeBean.id }
            deleteThemeValueByThemeId(item.themeBean.id)
            setThemeValue(item.themeConfigBeanList.values.toList())
        }
    }

    @Transaction
    fun setTheme(beans: List<ThemeWithValueResult>) {

        beans.forEach { item ->
            if (item.themeBean.isUsed) {
                putIsUsedToFalse()
            }
            val id = set(item.themeBean).toInt()
            item.themeConfigBeanList.values.forEach { it.themeId = id }
            setThemeValue(item.themeConfigBeanList.values.toList())
        }
    }

    //endregion
}